home *** CD-ROM | disk | FTP | other *** search
/ Enter 2006 September / Enter 09 2006.iso / Internet / SpamExperts Home 1.1 / SpamExperts Home.exe / lib / spamexperts.modules / wxp.pyc (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2006-07-14  |  28.6 KB  |  870 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.4)
  3.  
  4. from __future__ import division
  5. import re
  6. import sys
  7. import types
  8. import images
  9. import string
  10. import locale
  11. import textwrap
  12. import wx
  13. import wx.lib.buttons as wx
  14. import wx.lib.hyperlink as hl
  15. import wx.lib.mixins.listctrl as listmix
  16. from spamexperts.Options import options
  17.  
  18. def progress_update_wrapper(dlg):
  19.     
  20.     def update(*args):
  21.         dlg.Update(*args)
  22.         (new_w, new_h) = dlg.GetBestSize()
  23.         (w, h) = dlg.GetSize()
  24.         dlg.SetSize((max(w, new_w), max(new_h, h)))
  25.  
  26.     return update
  27.  
  28.  
  29. def wrap(s, length = 70):
  30.     '''A simple wordwrap function.  Provides more natural results
  31.     than textwrap.wrap().'''
  32.     line = ''
  33.     lines = []
  34.     for word in s.split(' '):
  35.         if '\n' in word:
  36.             parts = word.split('\n')
  37.             if len(line) + len(parts[0]) <= length:
  38.                 line += parts[0]
  39.                 parts = parts[1:]
  40.             
  41.             lines.append(line)
  42.             line = parts[-1] + ' '
  43.             continue
  44.         None if len(parts) > 1 else []
  45.         if len(line) + len(word) <= length:
  46.             line += word + ' '
  47.             continue
  48.         lines.append(line[:-1])
  49.         line = word + ' '
  50.     
  51.     lines.append(line)
  52.     return lines
  53.  
  54.  
  55. def fill(s, length = 70):
  56.     return '\n'.join(wrap(s, length))
  57.  
  58.  
  59. class DigitValidator(wx.PyValidator):
  60.     valid_characters = string.digits
  61.     
  62.     def __init__(self):
  63.         wx.PyValidator.__init__(self)
  64.         self.Bind(wx.EVT_CHAR, self.OnChar)
  65.  
  66.     
  67.     def Clone(self):
  68.         return DigitValidator()
  69.  
  70.     
  71.     def Validate(self, win):
  72.         tc = self.GetWindow()
  73.         val = tc.GetValue()
  74.         for x in val:
  75.             if x not in self.valid_characters:
  76.                 return False
  77.                 continue
  78.         
  79.         return True
  80.  
  81.     
  82.     def OnChar(self, event):
  83.         key = event.KeyCode()
  84.         if key in [
  85.             wx.WXK_BACK,
  86.             wx.WXK_DELETE] or key > 255:
  87.             event.Skip()
  88.             return None
  89.         
  90.         if chr(key) in self.valid_characters:
  91.             event.Skip()
  92.             return None
  93.         
  94.         if not wx.Validator_IsSilent():
  95.             wx.Bell()
  96.         
  97.  
  98.  
  99.  
  100. class DigitsValidator(DigitValidator):
  101.     valid_characters = string.digits + ','
  102.     
  103.     def Clone(self):
  104.         return DigitsValidator()
  105.  
  106.  
  107.  
  108. class AutoWidthSortedLC(wx.ListCtrl, listmix.ColumnSorterMixin):
  109.     
  110.     def __init__(self, parent, style = wx.LC_REPORT | wx.LC_SORT_ASCENDING | wx.LC_VRULES | wx.LC_HRULES, nocols = 6):
  111.         wx.ListCtrl.__init__(self, parent, style = style)
  112.         listmix.ColumnSorterMixin.__init__(self, nocols)
  113.         self.il = wx.ImageList(16, 16)
  114.         self.sm_up = self.il.Add(images.getSmallUpArrowBitmap())
  115.         self.sm_dn = self.il.Add(images.getSmallDnArrowBitmap())
  116.         self.SetImageList(self.il, wx.IMAGE_LIST_SMALL)
  117.         self.place = None
  118.         self.active_item = 0
  119.  
  120.     
  121.     def DeselectAll(self):
  122.         self.selecting = True
  123.         for i in range(self.GetItemCount()):
  124.             self.SetItemState(i, 0, wx.LIST_STATE_SELECTED)
  125.         
  126.         self.selecting = False
  127.  
  128.     
  129.     def GetListCtrl(self):
  130.         return self
  131.  
  132.     
  133.     def GetSortImages(self):
  134.         return (self.sm_dn, self.sm_up)
  135.  
  136.     
  137.     def GetColumnSorter(self):
  138.         '''Returns a callable object to be used for comparing column values when sorting.'''
  139.         return self._AutoWidthSortedLC__ColumnSorter
  140.  
  141.     
  142.     def __ColumnSorter(self, key1, key2):
  143.         '''Like the wx.lib.mixins.listctrl.ColumnSorterMixin method, but
  144.         case insensitive.'''
  145.         col = self._col
  146.         ascending = self._colSortFlag[col]
  147.         item1 = self.itemDataMap[key1]
  148.         item2 = self.itemDataMap[key2]
  149.         if type(item1) == type('') or type(item2) == type(''):
  150.             cmpVal = locale.strcoll(str(item1).lower(), str(item2).lower())
  151.         else:
  152.             cmpVal = cmp(item1, item2)
  153.         if cmpVal == 0:
  154.             cmpVal = apply(cmp, self.GetSecondarySortValues(col, key1, key2))
  155.         
  156.         if ascending:
  157.             return cmpVal
  158.         else:
  159.             return -cmpVal
  160.  
  161.     
  162.     def MoveSelectionUp(self, deselect = True):
  163.         if self.place is None:
  164.             self.place = self.GetFocusedItem()
  165.         
  166.         next = self.GetNextItem(self.GetFocusedItem(), wx.LIST_NEXT_ABOVE)
  167.         self.active_item = next
  168.         if next > -1:
  169.             self.DeselectAll()
  170.             if deselect:
  171.                 self.place = None
  172.                 self.Select(next)
  173.             
  174.             self.Focus(next)
  175.             self.EnsureVisible(next)
  176.             if self.place is not None:
  177.                 start = min(self.place, self.GetFocusedItem())
  178.                 stop = max(self.place, self.GetFocusedItem()) + 1
  179.                 for i in xrange(start, stop):
  180.                     self.Select(i)
  181.                 
  182.             
  183.         
  184.  
  185.     
  186.     def MoveSelectionDown(self, deselect = True):
  187.         if self.place is None:
  188.             self.place = self.GetFocusedItem()
  189.         
  190.         next = self.GetNextItem(self.GetFocusedItem(), wx.LIST_NEXT_BELOW)
  191.         self.active_item = next
  192.         if next > -1:
  193.             self.DeselectAll()
  194.             if deselect:
  195.                 self.place = None
  196.                 self.Select(next)
  197.             
  198.             self.Focus(next)
  199.             self.EnsureVisible(next)
  200.             if self.place is not None:
  201.                 start = min(self.place, self.GetFocusedItem())
  202.                 stop = max(self.place, self.GetFocusedItem()) + 1
  203.                 for i in xrange(start, stop):
  204.                     self.Select(i)
  205.                 
  206.             
  207.         
  208.  
  209.  
  210.  
  211. class SortedLC(wx.ListCtrl, listmix.ColumnSorterMixin):
  212.     
  213.     def __init__(self, parent, style = wx.LC_REPORT | wx.LC_SORT_ASCENDING | wx.LC_VRULES | wx.LC_HRULES, nocols = 6):
  214.         wx.ListCtrl.__init__(self, parent, style = style)
  215.         self.itemDataMap = []
  216.         listmix.ColumnSorterMixin.__init__(self, nocols)
  217.         self.il = wx.ImageList(16, 16)
  218.         self.sm_up = self.il.Add(images.getSmallUpArrowBitmap())
  219.         self.sm_dn = self.il.Add(images.getSmallDnArrowBitmap())
  220.         self.SetImageList(self.il, wx.IMAGE_LIST_SMALL)
  221.         self.place = None
  222.         self.active_item = 0
  223.  
  224.     
  225.     def DeselectAll(self):
  226.         self.selecting = True
  227.         for i in range(self.GetItemCount()):
  228.             self.SetItemState(i, 0, wx.LIST_STATE_SELECTED)
  229.         
  230.         self.selecting = False
  231.  
  232.     
  233.     def SelectAll(self):
  234.         self.selecting = True
  235.         for i in range(self.GetItemCount()):
  236.             self.SetItemState(i, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED)
  237.         
  238.         self.selecting = False
  239.  
  240.     
  241.     def GetSelectedMsgs(self):
  242.         ret = []
  243.         index = self.GetFirstSelected()
  244.         while index != -1:
  245.             ret.append(self.itemDataMap[self.GetItemData(index)])
  246.             index = self.GetNextSelected(index)
  247.         return ret
  248.  
  249.     
  250.     def GetFocusedMsg(self):
  251.         focused = self.GetFocusedItem()
  252.         if focused == -1:
  253.             focused = self.GetFirstSelected()
  254.         
  255.         return self.itemDataMap[self.GetItemData(focused)]
  256.  
  257.     
  258.     def MoveSelectionUp(self, deselect = True):
  259.         if self.place is None:
  260.             self.place = self.GetFocusedItem()
  261.         
  262.         next = self.GetNextItem(self.GetFocusedItem(), wx.LIST_NEXT_ABOVE)
  263.         self.active_item = next
  264.         if next > -1:
  265.             self.DeselectAll()
  266.             if deselect:
  267.                 self.place = None
  268.                 self.Select(next)
  269.             
  270.             self.Focus(next)
  271.             self.EnsureVisible(next)
  272.             if self.place is not None:
  273.                 start = min(self.place, self.GetFocusedItem())
  274.                 stop = max(self.place, self.GetFocusedItem()) + 1
  275.                 for i in xrange(start, stop):
  276.                     self.Select(i)
  277.                 
  278.             
  279.         
  280.  
  281.     
  282.     def MoveSelectionDown(self, deselect = True):
  283.         if self.place is None:
  284.             self.place = self.GetFocusedItem()
  285.         
  286.         next = self.GetNextItem(self.GetFocusedItem(), wx.LIST_NEXT_BELOW)
  287.         self.active_item = next
  288.         if next > -1:
  289.             self.DeselectAll()
  290.             if deselect:
  291.                 self.place = None
  292.                 self.Select(next)
  293.             
  294.             self.Focus(next)
  295.             self.EnsureVisible(next)
  296.             if self.place is not None:
  297.                 start = min(self.place, self.GetFocusedItem())
  298.                 stop = max(self.place, self.GetFocusedItem()) + 1
  299.                 for i in xrange(start, stop):
  300.                     self.Select(i)
  301.                 
  302.             
  303.         
  304.  
  305.     
  306.     def GetListCtrl(self):
  307.         return self
  308.  
  309.     
  310.     def GetSortImages(self):
  311.         return (self.sm_dn, self.sm_up)
  312.  
  313.     
  314.     def GetColumnText(self, index, col):
  315.         item = list.GetItem(index, col)
  316.         return item.GetText()
  317.  
  318.     
  319.     def GetColumnSorter(self):
  320.         '''Returns a callable object to be used for comparing column values when sorting.'''
  321.         return self._SortedLC__ColumnSorter
  322.  
  323.     
  324.     def __ColumnSorter(self, key1, key2):
  325.         '''Like the wx.lib.mixins.listctrl.ColumnSorterMixin method, but
  326.         case insensitive.'''
  327.         col = self._col
  328.         ascending = self._colSortFlag[col]
  329.         item1 = self.itemDataMap[key1][col]
  330.         item2 = self.itemDataMap[key2][col]
  331.         if type(item1) == type('') or type(item2) == type(''):
  332.             cmpVal = locale.strcoll(str(item1).lower(), str(item2).lower())
  333.         else:
  334.             cmpVal = cmp(item1, item2)
  335.         if cmpVal == 0:
  336.             cmpVal = apply(cmp, self.GetSecondarySortValues(col, key1, key2))
  337.         
  338.         if ascending:
  339.             return cmpVal
  340.         else:
  341.             return -cmpVal
  342.  
  343.  
  344.  
  345. class BoxPanel(wx.Panel):
  346.     
  347.     def __init__(self, parent, dir = wx.VERTICAL, style = 0):
  348.         wx.Panel.__init__(self, parent, style = style)
  349.         self.sizer = wx.BoxSizer(dir)
  350.         self.SetSizer(self.sizer)
  351.         self.Add = self.sizer.Add
  352.         self.Layout = self.sizer.Layout
  353.         self.ShowComp = self.sizer.Show
  354.         self.HideComp = self.sizer.Hide
  355.  
  356.  
  357.  
  358. class EvidenceWindow(wx.Dialog):
  359.     
  360.     def __init__(self, parent, msg, state):
  361.         wx.Dialog.__init__(self, parent)
  362.         self.state = state
  363.         self.SetBackgroundColour(wx.WHITE)
  364.         self.report = []
  365.         score = float(msg[options[('Headers', 'score_header_name')]])
  366.         distance = abs(0.5 - score)
  367.         if distance <= distance:
  368.             pass
  369.         elif distance < 0.20000000000000001:
  370.             strength = _('not very')
  371.         elif distance <= distance:
  372.             pass
  373.         elif distance < 0.40000000000000002:
  374.             strength = _('fairly')
  375.         else:
  376.             strength = _('very')
  377.         label = _('SpamExperts was %s sure about this message, because:') % (strength,)
  378.         self.evidence_box = wx.StaticBox(self, -1, label)
  379.         self.bsizer = wx.StaticBoxSizer(self.evidence_box, wx.VERTICAL)
  380.         evidence = msg[options[('Headers', 'evidence_header_name')]]
  381.         if evidence:
  382.             self.check_evidence(msg, evidence)
  383.         
  384.         self.border = wx.BoxSizer(wx.VERTICAL)
  385.         classification = msg[options[('Headers', 'classification_header_name')]]
  386.         if not msg['Subject']:
  387.             pass
  388.         subject = state.get_header(_('{no subject}'))
  389.         if classification == options[('Headers', 'header_spam_string')]:
  390.             label = _('This message (%s) was classified as Spam.') % (subject,)
  391.         elif classification == options[('Headers', 'header_unsure_string')]:
  392.             label = _('This message (%s) was classified as Unsure.') % (subject,)
  393.         else:
  394.             label = _('This message (%s) was classified as Not Spam.') % (subject,)
  395.         self.add(label)
  396.         self.SetTitle(subject + _(': Evidence'))
  397.         self.check_training(evidence)
  398.         self.border.Add(self.bsizer, 1, wx.EXPAND | wx.ALL, 10)
  399.         self.SetSizer(self.border)
  400.         self.ok = wx.Button(self, wx.ID_OK)
  401.         self.copy = wx.Button(self, label = _('Copy evidence'))
  402.         self.border.Add(self.copy, 0, wx.ALIGN_CENTER | wx.ALL, 5)
  403.         self.border.Add(self.ok, 0, wx.ALIGN_CENTER | wx.ALL, 5)
  404.         self.copy.Bind(wx.EVT_BUTTON, self.OnCopy)
  405.         self.SetBestFittingSize()
  406.  
  407.     
  408.     def OnCopy(self, evt):
  409.         clip_text = wx.TextDataObject('\r\n'.join(self.report))
  410.         if wx.TheClipboard.Open():
  411.             wx.TheClipboard.SetData(clip_text)
  412.             wx.TheClipboard.Flush()
  413.             wx.TheClipboard.Close()
  414.             dlg = wx.MessageDialog(self, _('Copied.'), _('Success'), wx.OK)
  415.         else:
  416.             dlg = wx.MessageDialog(self, _('Copy failed.'), _('Success'), wx.OK)
  417.         dlg.ShowModal()
  418.         dlg.Destroy()
  419.  
  420.     
  421.     def check_evidence(self, msg, evidence):
  422.         if self.check_address(evidence):
  423.             return None
  424.         
  425.         if self.check_statistical(evidence):
  426.             return None
  427.         
  428.         if self.check_fingerprint(evidence, msg):
  429.             return None
  430.         
  431.         if self.check_dns(msg, evidence):
  432.             return None
  433.         
  434.         self.add_evidence(_('No evidence was able to be found.'))
  435.  
  436.     
  437.     def add(self, label):
  438.         self.report.append(label)
  439.         txt = wx.StaticText(self, -1, label)
  440.         txt.SetBestFittingSize()
  441.         self.border.Add(txt, 0, wx.ALIGN_LEFT | wx.ALL, 5)
  442.  
  443.     
  444.     def add_evidence(self, label):
  445.         self.report.append(label)
  446.         txt = wx.StaticText(self, -1, label)
  447.         self.bsizer.Add(txt, 0, wx.TOP | wx.LEFT, 10)
  448.  
  449.     address_re = re.compile("'address': (\\d\\.\\d+);?")
  450.     
  451.     def check_address(self, evidence):
  452.         mo = self.address_re.search(evidence)
  453.         if mo:
  454.             address_score = float(mo.group(1))
  455.             if address_score != 0.5:
  456.                 if address_score < 0.5:
  457.                     colour = _('whitelisted')
  458.                 else:
  459.                     colour = _('blacklisted')
  460.                 label = _('You have %s the address that this message is from.') % (colour,)
  461.                 self.add_evidence(label)
  462.                 return True
  463.             
  464.         
  465.         return False
  466.  
  467.     stat_count_re = re.compile("'\\*HAMCOUNT\\*': (\\d+)\\.00;.*'\\*SPAMCOUNT\\*': (\\d+)\\.00;?", re.DOTALL)
  468.     
  469.     def check_training(self, evidence):
  470.         mo = self.stat_count_re.search(evidence)
  471.         if mo:
  472.             hamcount = int(mo.group(1))
  473.             spamcount = int(mo.group(2))
  474.             if spamcount == spamcount:
  475.                 pass
  476.             elif spamcount == 0:
  477.                 ratio = 1
  478.             elif hamcount == 0:
  479.                 ratio = spamcount
  480.             elif spamcount == 0:
  481.                 ratio = hamcount
  482.             else:
  483.                 ratio = max(hamcount, spamcount) / min(hamcount, spamcount)
  484.             total = hamcount + spamcount
  485.             good = True
  486.             if ratio <= ratio:
  487.                 pass
  488.             elif ratio < 5:
  489.                 label = _('You have a good balance of Not Spam and Spam trained, ')
  490.             elif ratio <= ratio:
  491.                 pass
  492.             elif ratio < 10:
  493.                 label = _('Your training is a little imbalanced, ')
  494.             elif ratio <= ratio:
  495.                 pass
  496.             elif ratio < 50:
  497.                 label = _('Your training is very imbalanced, ')
  498.                 good = False
  499.             else:
  500.                 label = _('Your training is extremely imbalanced, ')
  501.                 good = False
  502.             if total <= total:
  503.                 pass
  504.             elif total < 10:
  505.                 if good:
  506.                     label += _('but ')
  507.                 else:
  508.                     label += _('and ')
  509.                 label += _('your system needs more training before it will be effective.')
  510.             elif total <= total:
  511.                 pass
  512.             elif total < 1000:
  513.                 label += _('your system is well trained.')
  514.             elif good:
  515.                 label += _('but ')
  516.             else:
  517.                 label += _('and ')
  518.             label += _('your system may be overtrained.')
  519.             self.add(label)
  520.         
  521.  
  522.     stats_re = re.compile("'statistical': (\\d\\.\\d+);?")
  523.     token_re = re.compile('(?:(?:\'(.+?)\')|(?:"(.+?)")): (\\d.\\d+)', re.DOTALL)
  524.     meta_tokens = ('address', 'statistical', '*H*', '*S*', '*HAMCOUNT*', '*SPAMCOUNT*', 'dns', 'fingerprint', 'RBL', 'SPF', 'DNS', 'SURBL', 'DomainKeys')
  525.     
  526.     def check_statistical(self, evidence):
  527.         mo = self.stats_re.search(evidence)
  528.         if mo:
  529.             stats_score = float(mo.group(1))
  530.             if stats_score != 0.5:
  531.                 distance = abs(0.5 - stats_score)
  532.                 if distance <= distance:
  533.                     pass
  534.                 elif distance < 0.20000000000000001:
  535.                     similiarity = _('a little')
  536.                 elif distance <= distance:
  537.                     pass
  538.                 elif distance < 0.40000000000000002:
  539.                     similiarity = _('somewhat')
  540.                 elif distance <= distance:
  541.                     pass
  542.                 elif distance <= 0.5:
  543.                     similiarity = _('a lot')
  544.                 
  545.                 if stats_score > 0.5:
  546.                     label = _('It looks %s like other Spam you have received.') % (similiarity,)
  547.                 else:
  548.                     label = _('It looks %s like other Not Spam you have received.') % (similiarity,)
  549.                 self.add_evidence(label)
  550.                 tokens = self.token_re.findall(evidence)
  551.                 tokens = _[1]
  552.                 tokens.sort()
  553.                 strong = []
  554.                 moderate = []
  555.                 weak = []
  556.                 for distance, token in tokens:
  557.                     if token.startswith('bi:'):
  558.                         token = token[3:]
  559.                     
  560.                     if distance < distance:
  561.                         pass
  562.                     elif distance < 0.10000000000000001:
  563.                         weak.append(token)
  564.                         continue
  565.                     if distance < distance:
  566.                         pass
  567.                     elif distance < 0.29999999999999999:
  568.                         moderate.append(token)
  569.                         continue
  570.                     if distance < distance:
  571.                         pass
  572.                     elif distance <= 0.5:
  573.                         strong.append(token)
  574.                         continue
  575.                 
  576.                 if strong:
  577.                     label = _('Strong clues included: ') + ','.join(strong)
  578.                     self.add_evidence(label)
  579.                 
  580.                 if moderate:
  581.                     label = _('Moderate clues included: ') + ','.join(moderate)
  582.                     self.add_evidence(label)
  583.                 
  584.                 if weak:
  585.                     label = _('Weak clues included: ') + ','.join(weak)
  586.                     self.add_evidence(label)
  587.                 
  588.                 return True
  589.             
  590.         
  591.         return False
  592.  
  593.     fingerprint_re = re.compile("'fingerprint': (\\d\\.\\d+);?")
  594.     ridges_re = re.compile('"FP:set\\(\\[([\\s\\d,\\\']*)\\]\\)": \\d+\\.\\d+;')
  595.     
  596.     def check_fingerprint(self, evidence, msg):
  597.         mo = self.fingerprint_re.search(evidence)
  598.         if mo:
  599.             fp_score = float(mo.group(1))
  600.             if fp_score != 0.5:
  601.                 if fp_score <= fp_score:
  602.                     pass
  603.                 elif fp_score < 0.80000000000000004:
  604.                     similiarity = _('a little')
  605.                 elif fp_score <= fp_score:
  606.                     pass
  607.                 elif fp_score < 0.90000000000000002:
  608.                     similiarity = _('somewhat')
  609.                 elif fp_score <= fp_score:
  610.                     pass
  611.                 elif fp_score <= 1.0:
  612.                     similiarity = _('a lot')
  613.                 
  614.                 label = _('It looked %s like Spam received by other SpamExperts users.  Text in red matches other Spam messages.') % (similiarity,)
  615.                 self.add_evidence(label)
  616.                 mo = self.ridges_re.search(evidence)
  617.                 return True
  618.             
  619.         
  620.         return False
  621.  
  622.     dns_re = re.compile("'dns': (\\d\\.\\d+);?")
  623.     
  624.     def check_dns(self, msg, evidence):
  625.         mo = self.dns_re.search(evidence)
  626.         if mo:
  627.             dns_score = float(mo.group(1))
  628.             if dns_score != 0.5:
  629.                 label = _('It came from a sender, or contained links, that other users have reported as Spam.')
  630.                 self.add_evidence(label)
  631.                 return True
  632.             
  633.         
  634.         return False
  635.  
  636.  
  637.  
  638. class SplitPanel(wx.SplitterWindow):
  639.     
  640.     def __init__(self, parent, model, ID = -1, style = wx.SP_LIVE_UPDATE):
  641.         wx.SplitterWindow.__init__(self, parent, ID, style = style)
  642.         self.sizer = wx.BoxSizer(wx.VERTICAL)
  643.         self.SetSizer(self.sizer)
  644.         self.Add = self.sizer.Add
  645.         self.Layout = self.sizer.Layout
  646.         self.ShowComp = self.sizer.Show
  647.         self.HideComp = self.sizer.Hide
  648.         self.model = model
  649.  
  650.     
  651.     def ShowEvidence(self, evt):
  652.         for id_list in self.list.GetSelectedMsgs():
  653.             for corpus in (self.model.state.hamCorpus, self.model.state.spamCorpus, self.model.state.unsureCorpus):
  654.                 
  655.                 try:
  656.                     msg = corpus.get(id_list[3])
  657.                 except IOError:
  658.                     msg = None
  659.  
  660.                 if msg is None:
  661.                     continue
  662.                 
  663.             
  664.             if msg is None:
  665.                 print >>sys.stderr, "Can't find message", id_list[3]
  666.                 continue
  667.             
  668.             
  669.             try:
  670.                 msg.load()
  671.             except IOError:
  672.                 print >>sys.stderr, "Can't load message", id_list[3]
  673.                 continue
  674.  
  675.             dlg = EvidenceWindow(self, msg, self.model.state)
  676.             dlg.Show()
  677.         
  678.  
  679.  
  680.  
  681. class LabeledHyperlink(BoxPanel):
  682.     
  683.     def __init__(self, parent, label, linkName, url):
  684.         BoxPanel.__init__(self, parent, wx.HORIZONTAL)
  685.         self.label = wx.StaticText(self, label = label)
  686.         self.Add(self.label)
  687.         self.Add(hl.HyperLinkCtrl(self, -1, linkName, URL = url))
  688.  
  689.     
  690.     def SetLabel(self, value):
  691.         self.label.SetLabel(value)
  692.         self.Layout()
  693.  
  694.  
  695.  
  696. class ImgButton(wx.lib.buttons.GenBitmapTextToggleButton):
  697.     
  698.     def __init__(self, parent, text, imgs, handler = None):
  699.         bmps = [
  700.             None,
  701.             None,
  702.             None,
  703.             None]
  704.         if isinstance(imgs, types.TupleType):
  705.             for idx in range(len(imgs)):
  706.                 bmps[idx] = imgs[idx].ConvertToBitmap()
  707.             
  708.         else:
  709.             bmps[0] = imgs.ConvertToBitmap()
  710.         wx.lib.buttons.GenBitmapTextToggleButton.__init__(self, parent, -1, bmps[0], text)
  711.         self.SetBezelWidth(3)
  712.         self.SetUseFocusIndicator(False)
  713.         (self.bmpSelected, self.bmpDisabled, self.bmpFocus) = bmps[1:]
  714.         self.handler = handler
  715.         self.Bind(wx.EVT_BUTTON, self.OnButton)
  716.  
  717.     
  718.     def OnButton(self, evt):
  719.         if self.handler is not None:
  720.             self.handler()
  721.         
  722.         evt.Skip()
  723.  
  724.     
  725.     def _GetLabelSize(self):
  726.         ''' used internally '''
  727.         (w, h) = self.GetTextExtent(self.GetLabel())
  728.         if not self.bmpLabel:
  729.             return (w, h, True)
  730.         
  731.         w_bmp = self.bmpLabel.GetWidth() + 2
  732.         h_bmp = self.bmpLabel.GetHeight() + 7
  733.         height = h + h_bmp
  734.         if w_bmp > w:
  735.             width = w_bmp
  736.         else:
  737.             width = w
  738.         return (width, height, True)
  739.  
  740.     
  741.     def DrawLabel(self, dc, width, height, dw = 0, dy = 0):
  742.         '''Draw label centered underneath image.'''
  743.         bmp = self.bmpLabel
  744.         if bmp != None:
  745.             if self.bmpDisabled and not self.IsEnabled():
  746.                 bmp = self.bmpDisabled
  747.             
  748.             if self.bmpFocus and self.hasFocus:
  749.                 bmp = self.bmpFocus
  750.             
  751.             if self.bmpSelected and not (self.up):
  752.                 bmp = self.bmpSelected
  753.             
  754.             bw = bmp.GetWidth()
  755.             bh = bmp.GetHeight()
  756.             if not self.up:
  757.                 dw = dy = self.labelDelta
  758.             
  759.             hasMask = bmp.GetMask() != None
  760.         else:
  761.             bw = bh = 0
  762.         dc.SetFont(self.GetFont())
  763.         if self.IsEnabled():
  764.             dc.SetTextForeground(self.GetForegroundColour())
  765.         else:
  766.             dc.SetTextForeground(wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT))
  767.         label = self.GetLabel()
  768.         (tw, th) = dc.GetTextExtent(label)
  769.         if not self.up:
  770.             dw = dy = self.labelDelta
  771.         
  772.         pos_y = 10 + dy
  773.         if bmp != None:
  774.             dc.DrawBitmap(bmp, (width - bw) / 2 + dw, pos_y, hasMask)
  775.             pos_y = pos_y + 2
  776.         
  777.         dc.DrawText(label, (width - tw) / 2 + dw, pos_y + bh)
  778.  
  779.  
  780.  
  781. class LeftLabeledTF(BoxPanel):
  782.     
  783.     def __init__(self, parent, label = '', size = (-1, -1), validator = wx.DefaultValidator):
  784.         BoxPanel.__init__(self, parent, wx.HORIZONTAL)
  785.         self.label = wx.StaticText(self, label = label)
  786.         self.tf = wx.TextCtrl(self, size = size, validator = validator)
  787.         self.Add(self.label, 0, wx.ALIGN_CENTER | wx.ALL, 0)
  788.         self.Add(self.tf, 1, wx.LEFT | wx.ALIGN_CENTER, 2)
  789.  
  790.     
  791.     def SetLabel(self, value):
  792.         self.label.SetLabel(value)
  793.         self.Layout()
  794.  
  795.     
  796.     def GetValue(self):
  797.         return self.tf.GetValue()
  798.  
  799.     
  800.     def SetValue(self, val):
  801.         self.tf.SetValue(val)
  802.  
  803.     
  804.     def Bind(self, *args):
  805.         self.tf.Bind(*args)
  806.  
  807.  
  808.  
  809. class LeftLabeledChoice(BoxPanel):
  810.     
  811.     def __init__(self, parent, label, choices):
  812.         BoxPanel.__init__(self, parent, wx.HORIZONTAL)
  813.         self.label = wx.StaticText(self, label = label)
  814.         self.ch = wx.Choice(self, choices = choices)
  815.         self.Add(self.label, 0, wx.ALIGN_CENTER | wx.ALL, 0)
  816.         self.Add(self.ch, 1, wx.LEFT, 2)
  817.  
  818.     
  819.     def SetLabel(self, value):
  820.         self.label.SetLabel(value)
  821.         self.Layout()
  822.  
  823.     
  824.     def GetSelection(self):
  825.         return self.ch.GetStringSelection()
  826.  
  827.     
  828.     def SetStringSelection(self, val):
  829.         self.ch.SetStringSelection(val)
  830.  
  831.  
  832.  
  833. class StaticBoxGrid(wx.Panel):
  834.     
  835.     def __init__(self, parent, dir = wx.VERTICAL, style = 0, title = 'No Title'):
  836.         wx.Panel.__init__(self, parent, style = style)
  837.         self.innerSizer = wx.GridBagSizer(0, 0)
  838.         self.box = wx.StaticBox(self, label = title)
  839.         self.sizer = wx.StaticBoxSizer(self.box, dir)
  840.         self.sizer.Add(self.innerSizer, 1, wx.EXPAND)
  841.         self.SetSizer(self.sizer)
  842.  
  843.     
  844.     def SetTitle(self, value):
  845.         self.box.SetLabel(value)
  846.  
  847.     
  848.     def Add(self, *args, **kargs):
  849.         self.innerSizer.Add(*args, **kargs)
  850.  
  851.     
  852.     def Layout(self):
  853.         self.innerSizer.Layout()
  854.  
  855.  
  856.  
  857. def List2Menu(parent, list):
  858.     menu = wx.Menu()
  859.     for item in list:
  860.         if item:
  861.             (menuName, handler) = item
  862.             id = wx.NewId()
  863.             menu.Append(id, menuName)
  864.             parent.Bind(wx.EVT_MENU, handler, id = id)
  865.             continue
  866.         menu.AppendSeparator()
  867.     
  868.     return menu
  869.  
  870.